<template>
  <el-tabs type="border-card" class="demo-tabs">
    <el-tab-pane label="编码">
      <el-input v-model="textarea" style="width: 100%" :rows="2" type="textarea" placeholder="请输入文本" />
      <!-- AES加密密钥和IV输入 -->
      <div style="margin-top: 10px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
        <span style="font-weight: bold;">AES密钥：</span>
        <el-input v-model="aesKey" style="width: 300px" placeholder="请输入AES加密密钥" show-password />
        <el-button size="small" @click="generateRandomKey">生成随机密钥</el-button>
      </div>
      <div style="margin-top: 10px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
        <span style="font-weight: bold;">初始向量IV：</span>
        <el-input v-model="aesIV" style="width: 300px" placeholder="请输入AES初始化向量IV" />
        <el-button size="small" @click="generateRandomIV">生成随机IV</el-button>
        <el-tooltip content="AES/CBC/PKCS5Padding模式需要16字节IV" placement="top">
          <el-icon style="color: #909399; cursor: help;">
            <QuestionFilled />
          </el-icon>
        </el-tooltip>
      </div>
      <el-button type="primary" @click="enCodeBtn" style="margin-top: 10px;">编码</el-button>
      <el-card shadow="always" style="background-color: #f5f5f5; margin-top: 15px">
        <el-check-tag :checked="checked1" type="primary" @change="onChange1"> Base64 </el-check-tag>
        <el-check-tag :checked="checked2" type="success" @change="onChange2" style="margin-left: 10px">
          Url
        </el-check-tag>
        <el-check-tag :checked="checked4" type="warning" @change="onChange4" style="margin-left: 10px">
          Unicode(\u)
        </el-check-tag>
        <el-check-tag :checked="checked5" type="danger" @change="onChange5" style="margin-left: 10px">
          AES
        </el-check-tag>

        <div v-for="(item, index) in checkData" :key="index">
          <span class="label-name">{{ item.label }}</span>
          <el-input v-model="item.checkedValue" style="width: 800px; margin-left: 10px" placeholder="Please input" />
          <el-button type="primary" style="margin-left: 10px" @click="copyBtn(item.checkedValue)">复制</el-button>
        </div>
      </el-card>
    </el-tab-pane>

    <el-tab-pane label="解码">
      <el-input v-model="textareaD" style="width: 100%" :rows="2" type="textarea" placeholder="请输入文本" />
      <!-- AES解密密钥和IV输入 -->
      <div style="margin-top: 10px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
        <span style="font-weight: bold;">AES密钥：</span>
        <el-input v-model="aesKeyD" style="width: 300px" placeholder="请输入AES解密密钥" show-password />
      </div>
      <div style="margin-top: 10px; display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
        <span style="font-weight: bold;">初始向量IV：</span>
        <el-input v-model="aesIVD" style="width: 300px" placeholder="请输入AES初始化向量IV" />
        <el-tooltip content="需要与加密时使用的IV相同" placement="top">
          <el-icon style="color: #909399; cursor: help;">
            <QuestionFilled />
          </el-icon>
        </el-tooltip>
      </div>
      <el-button type="primary" @click="deCodeBtn" style="margin-top: 10px;">解码</el-button>
      <el-card shadow="always" style="background-color: #f5f5f5; margin-top: 15px">
        <el-check-tag :checked="checked1d" type="primary" @change="onChange1d">
          Base64
        </el-check-tag>
        <el-check-tag :checked="checked2d" type="success" @change="onChange2d" style="margin-left: 10px">
          Url
        </el-check-tag>
        <el-check-tag :checked="checked4d" type="warning" @change="onChange4d" style="margin-left: 10px">
          Unicode(\u)
        </el-check-tag>
        <el-check-tag :checked="checked5d" type="danger" @change="onChange5d" style="margin-left: 10px">
          AES
        </el-check-tag>

        <div v-for="(item, index) in checkDataD" :key="index">
          <span class="label-name">{{ item.label }}</span>
          <el-input v-model="item.checkedValue" style="width: 800px; margin-left: 10px" placeholder="Please input" />
          <el-button type="primary" style="margin-left: 10px" @click="copyDBtn(item.checkedValue)">复制</el-button>
        </div>
      </el-card>
    </el-tab-pane>
  </el-tabs>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import CryptoJS from 'crypto-js'
import { ElMessage } from 'element-plus'
import { QuestionFilled } from '@element-plus/icons-vue'

const textarea = ref('')
const textareaD = ref('')
const aesKey = ref('') // AES加密密钥
const aesKeyD = ref('') // AES解密密钥
const aesIV = ref('') // AES加密初始化向量
const aesIVD = ref('') // AES解密初始化向量

const checkData = ref([
  {
    label: 'Base64',
    index: 1,
    checkedValue: '',
  },
])
const checkDataD = ref([
  {
    label: 'Base64',
    index: 1,
    checkedValue: '',
  },
])

const checked1 = ref(true)
const checked2 = ref(false)
const checked4 = ref(false)
const checked5 = ref(false) // AES加密选项
const checked1d = ref(true)
const checked2d = ref(false)
const checked4d = ref(false)
const checked5d = ref(false) // AES解密选项

const onChange1 = (status: boolean) => {
  checked1.value = status

  let changeData = {
    label: 'Base64',
    index: 1,
    show: status,
    checkedValue: '',
  }
  showData(changeData)
}

const onChange2 = (status: boolean) => {
  checked2.value = status
  let changeData = {
    label: 'Url',
    index: 2,
    show: status,
    checkedValue: '',
  }
  showData(changeData)
}

const onChange4 = (status: boolean) => {
  checked4.value = status
  let changeData = {
    label: 'Unicode',
    index: 4,
    show: status,
    checkedValue: '',
  }
  showData(changeData)
}

const onChange5 = (status: boolean) => {
  checked5.value = status
  let changeData = {
    label: 'AES',
    index: 5,
    show: status,
    checkedValue: '',
  }
  showData(changeData)
}

const onChange1d = (status: boolean) => {
  checked1d.value = status

  let changeData = {
    label: 'Base64',
    index: 1,
    show: status,
    checkedValue: '',
  }
  showDataD(changeData)
}

const onChange2d = (status: boolean) => {
  checked2d.value = status
  let changeData = {
    label: 'Url',
    index: 2,
    show: status,
    checkedValue: '',
  }
  showDataD(changeData)
}

const onChange4d = (status: boolean) => {
  checked4d.value = status
  let changeData = {
    label: 'Unicode',
    index: 4,
    show: status,
    checkedValue: '',
  }
  showDataD(changeData)
}

const onChange5d = (status: boolean) => {
  checked5d.value = status
  let changeData = {
    label: 'AES',
    index: 5,
    show: status,
    checkedValue: '',
  }
  showDataD(changeData)
}

const showData = (changeData: any) => {
  let cacheShow = checkData.value

  if (!changeData.show) {
    for (let index = 0; index < cacheShow.length; index++) {
      let element = cacheShow[index]
      if (element.index === changeData.index) {
        cacheShow.splice(index, 1)
        break
      }
    }
  } else {
    let flag = false
    for (let index = 0; index < cacheShow.length; index++) {
      let element = cacheShow[index]
      if (element.index === changeData.index) {
        flag = true
        element.checkedValue = changeData.value
      }
    }
    if (!flag) {
      cacheShow.push(changeData)
    }
  }

  cacheShow.sort((a, b) => {
    return a.index - b.index
  })
  checkData.value = cacheShow
}

const showDataD = (changeData: any) => {
  let cacheShow = checkDataD.value

  if (!changeData.show) {
    for (let index = 0; index < cacheShow.length; index++) {
      let element = cacheShow[index]
      if (element.index === changeData.index) {
        cacheShow.splice(index, 1)
        break
      }
    }
  } else {
    let flag = false
    for (let index = 0; index < cacheShow.length; index++) {
      let element = cacheShow[index]
      if (element.index === changeData.index) {
        flag = true
        element.checkedValue = changeData.value
      }
    }
    if (!flag) {
      cacheShow.push(changeData)
    }
  }

  cacheShow.sort((a, b) => {
    return a.index - b.index
  })
  checkDataD.value = cacheShow
}

const copyBtn = (index: string) => {
  copyTxtTo(index)
}

const copyDBtn = (index: string) => {
  copyTxtTo(index)
}

const copyTxtTo = (text: string) => {
  console.log('已复制', text)

  try {
    navigator.clipboard.writeText(text)
  } catch (err) {
    console.error('复制失败: ', err)
  }
}

const enCodeBtn = () => {
  encodeText()
}

const encodeText = () => {
  let text = textarea.value
  console.log('text = ', text)
  checkData.value.forEach((element) => {
    if (element.index === 1) {
      element.checkedValue = btoa(encodeURIComponent(text))
    } else if (element.index === 2) {
      element.checkedValue = encodeURIComponent(text)
    } else if (element.index === 4) {
      if (text.length > 0) {
        element.checkedValue = ''
      }
      for (let i = 0; i < text.length; i++) {
        element.checkedValue += '\\u' + text.charCodeAt(i).toString(16)
      }
    } else if (element.index === 5) {
      // AES/CBC/PKCS5Padding加密
      try {
        if (!aesKey.value) {
          ElMessage.warning('请输入AES密钥')
          element.checkedValue = ''
          return
        }
        
        if (!aesIV.value) {
          ElMessage.warning('请输入AES初始化向量IV')
          element.checkedValue = ''
          return
        }

        // 使用CBC模式，需要IV
        const key = CryptoJS.enc.Utf8.parse(aesKey.value)
        const iv = CryptoJS.enc.Utf8.parse(aesIV.value)
        
        const encrypted = CryptoJS.AES.encrypt(text, key, {
          iv: iv,
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7  // PKCS5和PKCS7在AES中是等价的
        }).toString()
        
        element.checkedValue = encrypted
      } catch (error) {
        console.error('AES/CBC/PKCS5Padding加密失败:', error)
        ElMessage.error('AES加密失败')
        element.checkedValue = ''
      }
    }
  })
}

const deCodeBtn = () => {
  decodeText()
}

const decodeText = () => {
  let text = textareaD.value

  checkDataD.value.forEach((element) => {
    if (element.index === 1) {
      try {
        element.checkedValue = decodeURIComponent(atob(text))
      } catch (err) {
        console.error('Base64解码失败:', err)
        element.checkedValue = '解码失败'
      }
    } else if (element.index === 2) {
      try {
        element.checkedValue = decodeURIComponent(text)
      } catch (err) {
        console.error('URL解码失败:', err)
        element.checkedValue = '解码失败'
      }
    } else if (element.index === 4) {
      try {
        console.log('text = ', text)
        let num = text.split('\\u')
        console.log('num = ', num)
        let msg = ''
        num.forEach((element) => {
          if (element.length > 0) {
            msg += String.fromCharCode(parseInt(element, 16))
          }
        })
        element.checkedValue = msg
      } catch (err) {
        console.error('Unicode解码失败:', err)
        element.checkedValue = '解码失败'
      }
    } else if (element.index === 5) {
      // AES/CBC/PKCS5Padding解密
      try {
        if (!aesKeyD.value) {
          ElMessage.warning('请输入AES密钥')
          element.checkedValue = ''
          return
        }
        
        if (!aesIVD.value) {
          ElMessage.warning('请输入AES初始化向量IV')
          element.checkedValue = ''
          return
        }

        // 使用CBC模式解密，需要IV
        const key = CryptoJS.enc.Utf8.parse(aesKeyD.value)
        const iv = CryptoJS.enc.Utf8.parse(aesIVD.value)
        
        const decryptedBytes = CryptoJS.AES.decrypt(text, key, {
          iv: iv,
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7  // PKCS5和PKCS7在AES中是等价的
        })
        const decryptedText = decryptedBytes.toString(CryptoJS.enc.Utf8)

        if (!decryptedText) {
          throw new Error('解密结果为空，可能密钥或IV错误，或数据损坏')
        }
        element.checkedValue = decryptedText
      } catch (error) {
        console.error('AES/CBC/PKCS5Padding解密失败:', error)
        ElMessage.error('AES解密失败，请检查密钥和IV是否正确')
        element.checkedValue = '解密失败'
      }
    }
  })
}

// 生成随机AES密钥
const generateRandomKey = () => {
  const key = CryptoJS.lib.WordArray.random(256 / 8).toString()
  aesKey.value = key
  aesKeyD.value = key // 同步到解密密钥
  ElMessage.success('已生成随机密钥')
}

// 生成随机IV
const generateRandomIV = () => {
  // AES块大小为128位（16字节），生成16字节的随机IV
  const iv = CryptoJS.lib.WordArray.random(128 / 8).toString()
  aesIV.value = iv
  aesIVD.value = iv // 同步到解密IV
  ElMessage.success('已生成随机IV')
}

</script>

<style>
.demo-tabs>.el-tabs__content {
  padding: 32px;
  color: #6b778c;
  font-size: 32px;
  font-weight: 600;
}

.label-name {
  width: 80px;
  font-size: 20px;
  display: inline-block;
}
</style>
